/**
 * 
 */
package edu.gtcfla.km.repositories.hibernate4;

import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Repository;
import org.vsg.biz.BusinessEntityFactory;
import org.vsg.biz.utils.RepoInjectManager;
import org.vsg.common.orm.hibernate4.HibernateSessionManager;
import org.vsg.common.page.PaginationManager;

import edu.gtcfla.km.Category;
import edu.gtcfla.km.model.CategoryD;

/**
 * @author Bill Vison
 *
 */
@Repository(value="edu.gtcfla.km.repositories.categoryRepo")
public class CategoryRepoImpl<T extends Category, ID extends Serializable>  implements edu.gtcfla.km.repositories.CategoryRepo<T, ID> {

	
	@Autowired
	private ApplicationContext ctx;
	
	@Autowired	
	private BusinessEntityFactory entityFactory;
	
	@Autowired(required=false)
	private PaginationManager paginationManager;

	private HibernateSessionManager sessionManager;
	

	private static final Logger logger = LoggerFactory.getLogger(CategoryRepoImpl.class);

	@Autowired
	public void setSessionFactory(SessionFactory sessionFactory) {
		sessionManager = new HibernateSessionManager(sessionFactory);
	}		

	@Override
	public void save(T entity) {

		Session session = sessionManager.getSession();
	
		if (entity instanceof CategoryD) {
			CategoryD domainD = (CategoryD)entity;

			ID id = (ID)session.save(domainD);
	
 			RepoInjectManager injectManager = new RepoInjectManager(ctx);		
			injectManager.injectSingle(entity);		
		}
		
	}


	@Override
	public void update(T entity) {
		Session session = sessionManager.getSession();
		
		if (entity instanceof CategoryD) {
			CategoryD domainD = (CategoryD)entity;

			session.update(session.merge(domainD));
	
			RepoInjectManager injectManager = new RepoInjectManager(ctx);		
			injectManager.injectSingle(entity);		
		}		
	}


	@Override
	public void updateAll(Collection<T> entities) {
		// TODO Auto-generated method stub
		Session sess = sessionManager.getSession();

		for (T item : entities) {
			if ( ! ( item instanceof CategoryD )) {
				sess.update( sess.merge( item ) );
			} else {
				sess.update (sess.merge( item ));
			}
		}
		
	}


	@Override
	public T findOne(ID primaryKey) {
		Session session = sessionManager.getSession();

		T entity = (T)session.get( CategoryD.class, primaryKey);
		RepoInjectManager injectManager = new RepoInjectManager(ctx);		
		injectManager.injectSingle(entity);	
		
		return entity;
	}


	@Override
	public T findParent(ID primaryKey) {
		StringBuilder query = new StringBuilder("select ");
		query.append("parent.id , parent.name , parent.createdDate , parent.createdUserId , ");
		query.append("from ").append(CategoryD.class.getName()).append(" as entity ");
		query.append("left join entity.parentD as parent ");

		query.append("where entity.id = :id"); 


		logger.debug("query : " + query.toString());
		
		Session sess = sessionManager.getSession();
		
		Query hql = sess.createQuery( query.toString() );
		hql.setParameter("id", primaryKey);

		Iterator<Object[]> iterRes = (Iterator<Object[]>) hql.iterate();
		
		T result = null;
		
		RepoInjectManager injectManager = new RepoInjectManager(ctx);		
	
		if (iterRes.hasNext()) {
			Object[] fields = (Object[])iterRes.next();
			// --- convert to dto ----
			CategoryD entity = new CategoryD();
			int i = 0;
			entity.setId( (String)fields[i++] );
			entity.setName( (String)fields[i++] );
			entity.setCreatedDate( (Date)fields[i++] );
			entity.setCreatedUserId( (String)fields[i++] );
			
			//entity.setParentD( (CategoryD)fields[i++] ); 
			
			// --- convert to dto ----
			injectManager.injectSingle( entity );
			
			result = (T)entity;

		}
		return result;
	}


	@Override
	public Map<String, T> findAllMap() {
		StringBuilder query = new StringBuilder("select ");
		query.append("entity.id , entity.name , entity.createdDate , entity.createdUserId , ");
		query.append("parent ");
		query.append("from ").append(CategoryD.class.getName()).append(" as entity ");
		query.append("left join entity.parentD as parent ");


		logger.debug("query : " + query.toString());
		
		Session sess = sessionManager.getSession();
		
		Query hql = sess.createQuery( query.toString() );

		Iterator<Object[]> iterRes = (Iterator<Object[]>) hql.iterate();
		
		Map<String , T> resultMap = new LinkedHashMap<String , T>();
		RepoInjectManager injectManager = new RepoInjectManager(ctx);	
		while (iterRes.hasNext()) {
			Object[] fields = iterRes.next();
			
			CategoryD entity = new CategoryD();
			int i = 0;
			entity.setId( (String)fields[i++] );
			entity.setName( (String)fields[i++] );
			entity.setCreatedDate( (Date)fields[i++] );
			entity.setCreatedUserId( (String)fields[i++] );
			
			entity.setParentD( (CategoryD)fields[i++] ); 
			
			// --- convert to dto ----
			injectManager.injectSingle( entity );
			resultMap.put( entity.getId() ,(T) entity);

		}
				
		return resultMap;
	}

	@Override
	public Map<String, T> findAllByIds(Set<String> ids) {
		// TODO Auto-generated method stub
		StringBuilder query = new StringBuilder("select ");
		query.append("entity.id , entity.name , entity.createdDate , entity.createdUserId , ");
		query.append("parent ");
		query.append("from ").append(CategoryD.class.getName()).append(" as entity ");
		query.append("left join entity.parentD as parent ");
		query.append("where entity.id in (:ids) ");


		logger.debug("query : " + query.toString());
		
		Session sess = sessionManager.getSession();
		
		Query hql = sess.createQuery( query.toString() );
		if (ids.isEmpty()) {
			ids.add("");
		} 
		hql.setParameterList("ids", ids);

		Iterator<Object[]> iterRes = (Iterator<Object[]>) hql.iterate();
		
		Map<String , T> resultMap = new LinkedHashMap<String , T>();
		RepoInjectManager injectManager = new RepoInjectManager(ctx);	
		while (iterRes.hasNext()) {
			Object[] fields = iterRes.next();
			
			CategoryD entity = new CategoryD();
			int i = 0;
			entity.setId( (String)fields[i++] );
			entity.setName( (String)fields[i++] );
			entity.setCreatedDate( (Date)fields[i++] );
			entity.setCreatedUserId( (String)fields[i++] );
			
			entity.setParentD( (CategoryD)fields[i++] ); 
			
			// --- convert to dto ----
			injectManager.injectSingle( entity );
			resultMap.put( entity.getId() ,(T) entity);

		}
				
		return resultMap;
	}

	@Override
	public void deleteFully(T entity) {
		// TODO Auto-generated method stub
		Session sess = sessionManager.getSession();
		sess.delete( entity );
	}



	
	

	
}
